﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Rappelz.GameServer
{
    public class QuestManager
    {
        public class RandomQuestInfo
        {
            // public void RandomQuestInfo(int)
            public int code;
            public int[] key = new int[QuestInstance.MaxRandomValue];
            public int[] value = new int[QuestInstance.MaxRandomValue];
            public bool is_dropped;
        }

// Enum           :   <unnamed-tag>, Type: int
// Data           :     constant 0x14, Constant, Type: int, QUEST_MAX
// Function       :   public void StructQuestManager(const struct StructQuestManager &)
// Function       :   public void StructQuestManager::StructQuestManager()
// Function       :   public void StructQuestManager::~StructQuestManager()
// Function       :   public void SetOwner(struct StructQuest::QuestEventHandler *)
        public bool DoEachActiveQuest(QMQuestFunctor fn)
        {
            foreach (Quest q in this.m_vActiveQuest)
            {
                fn.run(q);
            }
            return true;
        }

        public void SetMaxQuestID(int id)
        {
            this.m_QuestIdx = id;
        }

        public bool AddQuest(Quest quest)
        {
            int nQuestCode; // [sp+24h] [bp-4h]@1
            if (quest.m_QuestBase == null)
                return false;

            nQuestCode = quest.m_Instance.Code;

            if (quest.m_Instance.Code == 0)
            {
                Globals.Log.Error("Quest code is zero!");
                return false;
            }
            foreach (Quest q in m_vActiveQuest)
            {
                if (quest.m_Instance.Code == q.m_Instance.Code)
                {
//                     v11 = this.m_pHandler;
//                     if (this.m_pHandler != null)
//                         v12 = (int)&v11[-1018];
//                     else
//                         v12 = 0;
//                     v13 = (StructQuest *)FileLogHandler::GetFileLogHandler();
//                     v14 = v13->vfptr;
//                     v15 = nQuestCode;
//                     pQuest = v13;
//                     v16 = (*(int (__thiscall **)(int))(*(_DWORD *)v12 + 64))(v12);
//                     ((void (*)(StructQuest *, const char *, ...))v14[1].__vecDelDtor)(
//                     pQuest,
//                     "Duplicated active quest detected. PlayerUID(%d), QuestCode(%d)",
//                     v16,
//                     v15);
//                     v17 = v3->m_pHandler;
//                     if ( v17 )
//                         v18 = (int)&v17[-1018];
//                     else
//                         v18 = 0;
//                     (*(void (__cdecl **)(unsigned int))(*(_DWORD *)v18 + 64))(nQuestCode);
//                     v31 = "Duplicated active quest detected. PlayerUID(%d), QuestCode(%d)\n";
//                     goto LABEL_20;
                    return false;
                }
            }

            if (quest.m_Instance.nProgress == QuestInstance.QuestProgress.Finished)
            {
                if (this.m_hsFinishedQuest.ContainsKey(nQuestCode) && !quest.m_QuestBase.bIsRepeatable)
                {
//                     v9 = v3->m_pHandler;
//                     if ( v9 )
//                         v10 = (int)&v9[-1018];
//                     else
//                         v10 = 0;
//                     v20 = (StructQuest *)FileLogHandler::GetFileLogHandler();
//                     v21 = v20->vfptr;
//                     v22 = nQuestCode;
//                     pQuest = v20;
//                     v23 = (*(int (__thiscall **)(int))(*(_DWORD *)v10 + 64))(v10);
//                     ((void (*)(StructQuest *, const char *, ...))v21[1].__vecDelDtor)(
//                     pQuest,
//                     "Duplicated completed quest detected. PlayerUID(%d), QuestCode(%d)",
//                     v23,
//                     v22);
//                     v24 = v3->m_pHandler;
//                     if ( v24 )
//                         v25 = (int)&v24[-1018];
//                     else
//                         v25 = 0;
//                     (*(void (__cdecl **)(unsigned int))(*(_DWORD *)v25 + 64))(nQuestCode);
//                     v31 = "Duplicated completed quest detected. PlayerUID(%d), QuestCode(%d)\n";
//                     LABEL_20:
//                     v19 = XConsole::Inst(0);
//                     XConsole::Printf(v19, v31);
                    return false;
                }

                this.m_hsFinishedQuest.Add(nQuestCode, true);
                return false;
            }
            if (Quest.IsRandomQuest(quest.m_Instance.Code))
            {
//                 v27 = (int)&v3->m_vRandomQuestInfo;
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                 &thisa,
//                 *(unsigned int **)(v27 + 4),
//                 (std::_Container_base *)v27);
//                 v39 = (signed int)thisa.baseclass_0.baseclass_0._Mycont;
//                 v35 = (std::_Container_base *)v27;
//                 v33 = *(unsigned int **)(v27 + 8);
//                 nQuestCode = (unsigned int)thisa._Myptr;
//                 while ( 1 )
//                 {
//                     std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     &thisa,
//                     v33,
//                     v35);
//                     if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                         (std::_Vector_const_iterator<ArObject *,std::allocator<ArObject *> > *)&v39,
//                         (std::_Vector_const_iterator<ArObject *,std::allocator<ArObject *> > *)&thisa) )
//                         break;
//                     if ( LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((std::_Vector_const_iterator<ArMoveVector::MOVE_INFO,std::allocator<ArMoveVector::MOVE_INFO> > *)&v39)->end.x) == v2 )
//                     {
//                         v28 = 0;
//                         do
//                         {
//                             v29 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((std::_Vector_const_iterator<ArMoveVector::MOVE_INFO,std::allocator<ArMoveVector::MOVE_INFO> > *)&v39);
//                             StructQuest::SetRandomKey(pQuest, v28, *((_DWORD *)&v29->end.y + v28));
//                             v30 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((std::_Vector_const_iterator<ArMoveVector::MOVE_INFO,std::allocator<ArMoveVector::MOVE_INFO> > *)&v39);
//                             StructQuest::SetRandomValue(pQuest, v28, *(&v30->end_time + v28));
//                             ++v28;
//                         }
//                         while ( v28 < 3 );
//                         v7 = (std::vector<unsigned int,std::allocator<unsigned int> > *)v38;
//                         break;
//                     }
//                     std::_Vector_const_iterator<LuaVM::LuaScriptInfo_std::allocator<LuaVM::LuaScriptInfo>>::operator__((std::_Vector_const_iterator<StructCreature::DamageReflectInfo,std::allocator<StructCreature::DamageReflectInfo> > *)&v39);
//                     v35 = (std::_Container_base *)v27;
//                     v33 = *(unsigned int **)(v27 + 8);
//                 }
            }
            m_vActiveQuest.Add(quest);
            return true;
        }
        public void AddRandomQuestInfo(int code, int[] key, int[] value, bool is_dropped)
        {

        }

        public bool StartQuest(int code, int nStartID)
        {
            if (code == 0 || this.FindQuest(code) != null)
                return false;

            int qid = this.allocQuestID();
            Quest q = Quest.AllocQuest(this.m_pHandler, qid, code, new int[6], QuestInstance.QuestProgress.InProgress, nStartID);
            if (Quest.IsRandomQuest(q.m_Instance.Code) )
            {
//                 v12 = v4->m_vRandomQuestInfo._Myfirst;
//                 v13 = &v4->m_vRandomQuestInfo;
//                 *(v3 + 11) = 1;
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v3 - 32),
//                     v12,
//                     v13);
//                 *(v3 - 40) = *(v3 - 32);
//                 *(v3 - 36) = *(v3 - 28);
//                 while ( 1 )
//                 {
//                     std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                         (v3 - 32),
//                         *(v13 + 8),
//                         v13);
//                     if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                              (v3 - 40),
//                              (v3 - 32)) )
//                     {
//                         StructQuestManager::RandomQuestInfo::RandomQuestInfo((v3 - 140), v5);
//                         std::vector<StructCreature::DamageReflectInfo_std::allocator<StructCreature::DamageReflectInfo>>::push_back(
//                             v13,
//                             v16);
//                         v17 = std::vector<StructQuestManager::RandomQuestInfo_std::allocator<StructQuestManager::RandomQuestInfo>>::back(v13);
//                         goto LABEL_10;
//                     }
//                     v14 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 40));
//                     v15 = (v3 - 40);
//                     if ( LODWORD(v14->end.x) == v5 )
//                         break;
//                     std::_Vector_const_iterator<LuaVM::LuaScriptInfo_std::allocator<LuaVM::LuaScriptInfo>>::operator__(v15);
//                 }
//                 v17 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(v15);
//                 *(v3 + 11) = *(v17 + 28) == 0;
//         LABEL_10:
//                 if ( *(v3 + 11) )
//                 {
//                     *(v3 - 28) = 0;
//                     *(v3 - 80) = 0;
//                     *(v3 - 76) = 0;
//                     *(v3 - 72) = 0;
//                     *(v3 - 4) = 0;
//                     v18 = (v17 + 4);
//                     v19 = 3;
//                     do
//                     {
//                         *(v18 + 12) = 0;
//                         *v18 = 0;
//                         v18 += 4;
//                         --v19;
//                     }
//                     while ( v19 );
//                     *(v3 - 16) = -14;
//                     *(v3 - 16) -= v17;
//                     *(v3 - 20) = -15;
//                     *(v3 - 20) -= v17;
//                     *(v3 + 8) = -16;
//                     *(v3 + 8) -= v17;
//                     *(v3 - 24) = 0;
//                     v20 = (v17 + 16);
//                     while ( 1 )
//                     {
//                         v21 = StructQuest::GetValue(*(v3 + 12), v20 + *(v3 + 8));
//                         *(v3 - 36) = v21;
//                         if ( v21 == v6 )
//                         {
//         LABEL_20:
//                             *(v3 - 4) = -1;
//                             std::vector<GameContent::REGEN_INFO_std::allocator<GameContent::REGEN_INFO>>::_Tidy((v3 - 84));
//                             goto LABEL_21;
//                         }
//                         if ( v21 != *(v3 - 28) )
//                             GameContent::GetRandomPoolInfo(v21, (v3 - 84), *(*(*(v3 + 12) + 4) + 16));
//                         if ( *(v3 - 80) == v6 )
//                             break;
//                         v22 = (*(v3 - 76) - *(v3 - 80)) >> 3;
//                         if ( !v22 )
//                             break;
//                         *(v3 - 28) = *(v3 - 36);
//                         v23 = XFastRandom() % v22;
//                         v24 = std::vector<XPerformanceGuard::_TAG_std::allocator<XPerformanceGuard::_TAG>>::operator__(
//                                   (v3 - 84),
//                                   v23);
//                         v25 = *(v3 + 12);
//                         *(v20 - 12) = v24->pObj;
//                         v26 = StructQuest::GetValue(v25, v20 + *(v3 - 16));
//                         v27 = StructQuest::GetValue(*(v3 + 12), v20 + *(v3 - 20));
//                         *v20 = XFastRandom(v27, v26);
//                         std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                             (v3 - 52),
//                             *(v3 - 80),
//                             (v3 - 84));
//                         v28 = std::_Vector_iterator<std::pair<int_int>_std::allocator<std::pair<int_int>>>::operator_(
//                                   (v3 - 52),
//                                   (v3 - 60),
//                                   v23);
//                         std::vector<GameContent::RANDOM_POOL_INFO_std::allocator<GameContent::RANDOM_POOL_INFO>>::erase(
//                             (v3 - 84),
//                             (v3 - 68),
//                             *v28);
//                         ++*(v3 - 24);
//                         v20 += 4;
//                         v6 = 0;
//                         if ( *(v3 - 24) >= 3 )
//                             goto LABEL_20;
//                     }
//                     StructQuest::FreeQuest(*(v3 + 12));
//                     std::vector<GameContent::REGEN_INFO_std::allocator<GameContent::REGEN_INFO>>::_Tidy((v3 - 84));
//                     return 0;
//                 }
//         LABEL_21:
//                 *(v17 + 28) = 0;
//                 v29 = (v17 + 16);
//                 do
//                 {
//                     StructQuest::SetRandomKey(*(v3 + 12), v6, *(v29 - 3));
//                     StructQuest::SetRandomValue(*(v3 + 12), v6++, *v29);
//                     ++v29;
//                 }
//                 while ( v6 < 3 );
//                 v4 = *(v3 - 44);
            }
            this.m_vActiveQuest.Add(q);
            return true;
        }

        public bool EndQuest(Quest pQuest)
        {
            pQuest.SetProgress(QuestInstance.QuestProgress.Finished);

            if(!this.m_hsFinishedQuest.ContainsKey(pQuest.m_Instance.Code))
                this.m_hsFinishedQuest.Add(pQuest.m_Instance.Code, true);
            return true;
        }
// Function       :   public bool DropQuest(int)


        public Quest FindQuest(int code)
        {
            foreach (Quest q in this.m_vActiveQuest)
            {
                if(q.m_QuestBase.nCode == code)
                    return q;
            }
            return null;
        }

        public bool IsFinishedQuest(int code)
        {
            if(this.m_hsFinishedQuest.ContainsKey(code))
                return this.m_hsFinishedQuest[code];
            return false;
        }

        public bool IsTakeableQuestItem(int code)
        {
// .text:00463659 this            = std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > ptr -10h
// .text:00463659 it              = std::_Vector_const_iterator<StructQuest *,std::allocator<StructQuest *> > ptr -8
// .text:00463659 code            = dword ptr  8

            foreach (Quest q in this.m_vActiveQuest)
            {
                if (q.m_Instance.nProgress == QuestInstance.QuestProgress.Finished
                  || q.m_QuestBase.nType != QuestBase.QuestType.Collect
                  && q.m_QuestBase.nType != QuestBase.QuestType.HuntItem
                  && q.m_QuestBase.nType != QuestBase.QuestType.HuntItemFromAnyMonsters
                  && q.m_QuestBase.nType != QuestBase.QuestType.RandomCollect
                  || q.IsFinishable())
                    continue;

                if (Quest.IsRandomQuest(q.m_QuestBase.nCode))
                {
                    if (q.GetRandomKey(0) == code
                      || q.GetRandomKey(1) == code
                      || q.GetRandomKey(2) == code)
                        return true;
                }
                else if (q.m_QuestBase.nType == QuestBase.QuestType.Collect)
                {
                    if (q.GetValue(0) == code
                      || q.GetValue(2) == code
                      || q.GetValue(4) == code
                      || q.GetValue(6) == code
                      || q.GetValue(8) == code
                      || q.GetValue(10) == code)
                        return true;
                }
                else
                {
                    if (q.GetValue(0) == code
                      || q.GetValue(2) == code
                      || q.GetValue(4) == code)
                        return true;
                }
            }
            return false;
        }

        public void GetRelatedQuest(List<Quest> vQuestList, int flag)
        {
            foreach (Quest q in this.m_vActiveQuest)
            {
                if (q.m_Instance.nProgress != QuestInstance.QuestProgress.Finished)
                {
                    if (GameContent.checkQuestTypeFlag(q.m_QuestBase.nType, flag))
                    {
                        vQuestList.Add(q);
                    }
                }
            }
        }


        public void GetRelatedQuestByItem(int code, List<Quest> vQuest, int flag)
        {
            foreach (Quest q in this.m_vActiveQuest)
            {
                if (q.m_Instance.nProgress == QuestInstance.QuestProgress.Finished || !GameContent.checkQuestTypeFlag(q.m_QuestBase.nType, flag))
                    continue;

                switch(q.m_QuestBase.nType)
                {
                    case QuestBase.QuestType.HuntItem:
                    case QuestBase.QuestType.HuntItemFromAnyMonsters:
                        if (q.GetValue(0) == code
                          || q.GetValue(2) == code
                          || q.GetValue(4) == code)
                            vQuest.Add(q);
                        break;

                    case QuestBase.QuestType.Collect:
                        if (q.GetValue(0) == code
                          || q.GetValue(2) == code
                          || q.GetValue(4) == code
                          || q.GetValue(6) == code
                          || q.GetValue(8) == code
                          || q.GetValue(10) == code)
                            vQuest.Add(q);
                        break;

                    case QuestBase.QuestType.RandomCollect:
                        if (q.GetRandomKey(0) == code
                          || q.GetRandomKey(1) == code
                          || q.GetRandomKey(2) == code)
                            vQuest.Add(q);
                        break;

                }
            }
        }

// Function       :   public void GetRelatedQuestBySkill(int, class std::vector<StructQuest *,std::allocator<StructQuest *> > &, int)
        public void GetRelatedQuestByMonster(int nMonsterId, List<Quest> vQuest, int flag)
        {
// .text:00464D5D this            = std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > ptr -10h
// .text:00464D5D it              = std::_Vector_iterator<StructQuest *,std::allocator<StructQuest *> > ptr -8
// .text:00464D5D nMonsterId      = dword ptr  8
// .text:00464D5D vQuestList      = dword ptr  0Ch
// .text:00464D5D flag            = dword ptr  10h
// 
// Data           :   ebp Relative, [00000008], Param, Type: int, nMonsterId
// Data           :   ebp Relative, [0000000C], Param, Type: class std::vector<StructQuest *,std::allocator<StructQuest *> > &, vQuestList
// Data           :   ebp Relative, [00000010], Param, Type: int, flag
// Data           :   ebp Relative, [FFFFFFF8], Local, Type: class std::_Vector_iterator<StructQuest *,std::allocator<StructQuest *> >, it
// 
            foreach (Quest q in this.m_vActiveQuest)
            {
                if (q.m_Instance.nProgress != QuestInstance.QuestProgress.Finished && GameContent.checkQuestTypeFlag(q.m_QuestBase.nType, flag))
                {
                    if (q.m_QuestBase.nType == QuestBase.QuestType.KillTotal || q.m_QuestBase.nType == QuestBase.QuestType.KillIndividual)
                    {
                        if (GameContent.IsInRandomPoolMonster(q.GetValue(0), nMonsterId) || GameContent.IsInRandomPoolMonster(q.GetValue(2), nMonsterId)|| GameContent.IsInRandomPoolMonster(q.GetValue(4), nMonsterId))
                            vQuest.Add(q);
                    }
                    else
                    {
                        if (q.m_QuestBase.nType != QuestBase.QuestType.HuntItem)
                        {
                            if (q.m_QuestBase.nType == QuestBase.QuestType.HuntItemFromAnyMonsters)
                                vQuest.Add(q);
                        }
                        else
                        {
                            if (GameContent.IsInRandomPoolMonster(q.GetValue(6), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(7), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(8), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(9), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(10), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(11), nMonsterId))
                                vQuest.Add(q);
                        }
                    }
                }
            }
        }

        public void UpdateQuestStatusByItemCount(int code, long count)
        {
            List<Quest> vQuestList = new List<Quest>(); // ptr -34h
            int i;

            this.GetRelatedQuestByItem(code, vQuestList, 6168);

            foreach (Quest q in vQuestList)
            {
                if (Quest.IsRandomQuest(q.m_QuestBase.nCode))
                {
                    for (i = 0; i < 6; ++i)
                    {
                        if (q.GetRandomKey(i) == code)
                        {
                            long qv = q.GetRandomValue(i);
                            if (count > qv)
                                count = qv;
                            q.UpdateStatus(i, (int)count);
                            return;
                        }
                    }
                }
                else
                {
                    for(i = 0; i < 6; ++i)
                    {
                        if (q.GetValue(2 * i) == code)
                        {
                            long qv = q.GetValue((2 * i) + 1);
                            if (count > qv)
                                count = qv;
                            q.UpdateStatus(i, (int)count);
                            return;
                        }
                    }
                }
            }
        }

        public void UpdateQuestStatusByMonsterKill(int nMonsterId)
        {
            List<Quest> vQuestList = new List<Quest>();

            this.GetRelatedQuest(vQuestList, 1030);

            foreach (Quest q in vQuestList)
            {
                if (q.m_Instance.nProgress != QuestInstance.QuestProgress.Finished && !q.IsFinishable())
                {
                    switch(q.m_QuestBase.nType)
                    {
                        case QuestBase.QuestType.KillTotal:
                            if ( (GameContent.IsInRandomPoolMonster(q.GetValue(0), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(2), nMonsterId)
                              || GameContent.IsInRandomPoolMonster(q.GetValue(4), nMonsterId))
                              && (q.GetStatus(0) < q.GetValue(1)))
                            {
                                q.IncStatus(0, 1);
                            }
                            break;

                        case QuestBase.QuestType.KillIndividual:
                            if ( GameContent.IsInRandomPoolMonster(q.GetValue(0), nMonsterId) && q.GetStatus(0) < q.GetValue(1))
                            {
                                q.IncStatus(0, 1);
                            }
                            else if ( GameContent.IsInRandomPoolMonster(q.GetValue(2), nMonsterId) && q.GetStatus(1) < q.GetValue(3))
                            {
                                q.IncStatus(1, 1);
                            }
                            else if (GameContent.IsInRandomPoolMonster(q.GetValue(4), nMonsterId) && q.GetStatus(2) < q.GetValue(5))
                            {
                                q.IncStatus(2, 1);
                            }
                            break;

                        case QuestBase.QuestType.RandomKillIndividual:
                            if (q.GetRandomKey(0) == nMonsterId && q.GetStatus(0) < q.GetRandomValue(0))
                            {
                                q.IncStatus(0, 1);
                            }
                            else if (q.GetRandomKey(1) == nMonsterId && q.GetStatus(1) < q.GetRandomValue(1))
                            {
                                q.IncStatus(1, 1);
                            }
                            else if (q.GetRandomKey(2) == nMonsterId && q.GetStatus(2) < q.GetRandomValue(2))
                            {
                                q.IncStatus(2, 1);
                            }
                            break;

                    }
                }
            }
        }

        public void UpdateQuestStatusBySkillLevel(int nSkillId, int nSkillLevel)
        {
            int v;
//            List<Quest> vQuestList = new List<Quest>();//      = std::vector<StructQuest *,std::allocator<StructQuest *> > ptr -30h
//            this.GetRelatedQuest(vQuestList, 32);
            foreach (Quest q in this.m_vActiveQuest)
            {
                if (q.m_Instance.nProgress != QuestInstance.QuestProgress.Finished && q.m_QuestBase.nType == QuestBase.QuestType.LearnSkill)
                {
                    if (q.GetValue(0) == nSkillId)
                    {
                        v = q.GetValue(1);
                        if (nSkillLevel > v)
                            nSkillLevel = v;
                        q.UpdateStatus(0, nSkillLevel);
                    }
                    else if (q.GetValue(2) == nSkillId)
                    {
                        v = q.GetValue(3);
                        if (nSkillLevel > v)
                            nSkillLevel = v;
                        q.UpdateStatus(1, nSkillLevel);
                    }
                    else if (q.GetValue(4) == nSkillId)
                    {
                        v = q.GetValue(5);
                        if (nSkillLevel > v)
                            nSkillLevel = v;
                        q.UpdateStatus(2, nSkillLevel);
                    }
                }
            }
        }

        public void UpdateQuestStatusByJobLevel(int nJobDepth, int nJobLevel)
        {
            int v;
            List<Quest> vQuestList = new List<Quest>();

            this.GetRelatedQuest(vQuestList, 256);

            foreach (Quest q in vQuestList)
            {
                if (q.m_Instance.nProgress != QuestInstance.QuestProgress.Finished && q.m_QuestBase.nType == QuestBase.QuestType.JobLevel)
                {
                    v = q.GetValue(0);
                    if (nJobDepth > v)
                        nJobDepth = v;
                    q.UpdateStatus(0, nJobDepth);

                    v = q.GetValue(1);
                    if (nJobLevel > v)
                        nJobLevel = v;
                    q.UpdateStatus(1, nJobLevel);
                }
            }
        }

        public void UpdateQuestStatusByParameter(int parameter_id, int value)
        {
            int v;
            List<Quest> vQuestList = new List<Quest>();

            this.GetRelatedQuest(vQuestList, 512);

            foreach (Quest q in vQuestList)
            {
                if (q.m_Instance.nProgress != QuestInstance.QuestProgress.Finished && q.m_QuestBase.nType == QuestBase.QuestType.Parameter)
                {
                    if (q.GetValue(0) == parameter_id)
                        q.UpdateStatus(0, value);
                    if (q.GetValue(3) == parameter_id)
                        q.UpdateStatus(1, value);
                    if (q.GetValue(6) == parameter_id)
                        q.UpdateStatus(2, value);
                }
            }
        }

        public void PopFromActiveQuest(Quest pQuest)
        {
            if(this.m_vActiveQuest.Contains(pQuest))
            {
                this.m_vActiveQuest.Remove(pQuest);
                pQuest.FreeQuest();
            }
        }

// Function       :   public unsigned int GetActiveQuestCount()

        public bool IsStartableQuest(int code)
        {
            bool res;

            if (this.FindQuest(code) != null)
                return false;
            QuestBaseServer qbs = Quest.GetQuestBase(code);
            if ( !qbs.bIsRepeatable && this.IsFinishedQuest(code))
                return false;
            res = true;
            if (qbs.bForeCheckType)
                res = false;
            for (int i = 0; i < QuestBase.MAX_FOREQUEST; ++i)
            {
                int id = qbs.nForeQuest[i];
                if (qbs.bForeCheckType)
                {
                    if (id != 0)
                    {
                        if (this.IsFinishedQuest(id))
                            return true;
                    }
                }
                else if (id != 0 && !this.IsFinishedQuest(id))
                    return false;
            }
            return res;
        }

        public void SetDropFlagToRandomQuestInfo(int code)
        {
            foreach (RandomQuestInfo rqi in this.m_vRandomQuestInfo)
            {
                if(rqi.code == code)
                {
                    rqi.is_dropped = true;
                    return;
                }
            }
        }

        public bool HasRandomQuestInfo(int code)
        {
            return false;
//             char *v2; // esi@1
//             unsigned int *v4; // [sp-8h] [bp-1Ch]@1
//             std::_Container_base *v5; // [sp-4h] [bp-18h]@1
//             std::_Vector_const_iterator<unsigned int,std::allocator<unsigned int> > thisa; // [sp+4h] [bp-10h]@1
//             std::_Vector_const_iterator<StructQuestManager::RandomQuestInfo,std::allocator<StructQuestManager::RandomQuestInfo> > it; // [sp+Ch] [bp-8h]@1
// 
//             v2 = &this->m_vRandomQuestInfo;
//             std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                 &thisa,
//                 this->m_vRandomQuestInfo._Myfirst,
//                 &this->m_vRandomQuestInfo.baseclass_0.___u0.baseclass_0);
//             it.baseclass_0.baseclass_0._Mycont = thisa.baseclass_0.baseclass_0._Mycont;
//             v5 = v2;
//             v4 = *(v2 + 2);
//             it._Myptr = thisa._Myptr;
//             while ( 1 )
//             {
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     &thisa,
//                     v4,
//                     v5);
//                 if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(&it, &thisa) )
//                     return 0;
//                 if ( LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it)->end.x) == code )
//                     break;
//                 std::_Vector_const_iterator<LuaVM::LuaScriptInfo_std::allocator<LuaVM::LuaScriptInfo>>::operator__(&it);
//                 v5 = v2;
//                 v4 = *(v2 + 2);
//             }
//             return 1;
        }
        
// Function       :   public bool NeedToUpdateRandomQuestInfo(int)
        public QuestEventHandler m_pHandler;// Data           :   this+0x4, Member, Type: struct StructQuest::QuestEventHandler *, m_pHandler

        protected int allocQuestID()
        {
            return Interlocked.Increment(ref this.m_QuestIdx);

        }

        public Dictionary<int, bool> m_hsFinishedQuest = new Dictionary<int, bool>();   // 0x8, Member, Type: class KHash<bool,khash_def::hashPr_mod_basic<int> >, 
        public List<Quest> m_vActiveQuest = new List<Quest>();                          // 0x24
        public int m_QuestIdx;                                                          // 0x34
        public List<RandomQuestInfo> m_vRandomQuestInfo = new List<RandomQuestInfo>();  // 0x38
    }
}
